"""
1.打开文件
open(file, mode='r', buffering=None, encoding=None, errors=None, newline=None, closefd=True)
Open file and return a stream. Raise OSError upon failure.
a. file : 必需，文件路径（相对或者绝对路径）。
b. mode : 可选，文件打开模式
c. buffering : 设置缓冲
d. encoding : 一般使用utf8
e. errors : 报错级别
f. newline : 区分换行符

mode
'r' 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。
'w' 打开一个文件只用于写入。
    如果该文件已存在则打开文件，并从开头开始编辑。
    即原有内容会被删除。
    如果该文件不存在，创建新文件。
'x' 写模式，新建一个文件，如果该文件已存在则会报错。
'a' 追加模式，打开一个文件用于追加。
    如果该文件已存在，文件指针将会放在文件的结尾。
    也就是说，新的内容将会被写入到已有内容之后。
    如果该文件不存在，创建新文件进行写入。
'b' 以二进制模式打开文件。一般用于非文本文件，如：图片。
't' 以文本模式打开（默认）。一般用于文本文件，如：txt。
'+' 可读写模式（可添加到其它模式中使用）

"""
f = open('1.open.json', mode='r+')
print(f.name)
content = f.read()
print(content)
print(type(content))

f.close()

f_qjj = open('1.将进酒.txt', mode='tr+', encoding='utf-8', )
print(f_qjj)

f_qjj.seek(0, 2)
author = '\n作者：liuhan'
f_qjj.write(author)
# for each in f_qjj:
#     print(each)

# 1.fileObject.read([size]) 用于从文件读取指定的字符数，如果未给定或为负则读取所有。
print("===========read=============")
s = f_qjj.read(20)
print("read(20) 读取的字符串: %s" % s)
# print(f_qjj.read())

# 2.fileObject.readline() 读取整行，包括 "\n" 字符。
print("===========readline=============")
f_qjj2 = open('1.将进酒.txt', mode='tr', encoding='utf-8', )
line = f_qjj2.readline()
print("readline 读取的字符串: %s" % line)

# 3.fileObject.readlines() 用于读取所有行(直到结束符 EOF)并返回列表，该列表可以由 Python 的
# for... in ... 结构进行处理。
print("===========readlines=============")
f_qjj3 = open('1.将进酒.txt', mode='tr', encoding='utf-8', )
lines = f_qjj3.readlines()
print(lines)

for each in lines:
    print('[' + each.strip() + "]")


# 4.fileObject.tell() 返回文件的当前位置，即文件指针当前位置。


def hand_num(file_object):
    return file_object.tell()


hand = hand_num(f_qjj2)
print('当前f_qjj2文件指针位置', hand)

"""
5. fileObject.seek(offset[, whence]) 用于移动文件读取指针到指定位置。
    a. offset ：开始的偏移量，也就是代表需要移动偏移的字节数，如果是负数表示从倒数第几位开始。
    b. whence ：可选，默认值为 0。给 offset 定义一个参数，表示要从哪个位置开始偏移；0 代表从文件开头开始
                算起，1 代表从当前位置开始算起，2 代表从文件末尾算起
"""
print("===========seek=============")
seek10_0 = f_qjj2.seek(10, 0)
print('seek10_0', seek10_0, hand_num(f_qjj2))
# seek20_1 = f_qjj2.seek(20, 1)  # io.UnsupportedOperation: can't do nonzero cur-relative seeks
# print('seek20_1', seek20_1, hand_num(f_qjj2))


"""
在文件关闭前或缓冲区刷新前，字符串内容存储在缓冲区中，这时你在文件中是看不到写入的内容的。
如果文件打开模式带 b ，那写入文件内容时， str （参数）要用 encode 方法转为 bytes 形式，否则报
错： TypeError: a bytes-like object is required, not 'str' 。

str = '...'
# 文本 = Unicode字符序列
# 相当于 string 类型
str = b'...'
# 文本 = 八位序列(0到255之间的整数)
# 字节文字总是以‘b’或‘B’作为前缀；它们产生一个字节类型的实例，而不是str类型。
# 相当于 byte[]
"""
# 6.fileObject.write(str) 用于向文件中写入指定字符串，返回的是写入的字符长度。

f_6 = open('workfile.txt', 'wb+')
print(f_6.write(b'abcdefgki'))  # 16
print(f_6.seek(5))  # 5
print(f_6.read(1))  # b'5'
print(f_6.seek(-3, 2))  # 13
print(f_6.read(1))  # b'd'
f_6.close()

f_qjj2.close()
f_qjj.close()
f_qjj3.close()

str1 = '...'
str2 = b'...'
print(str1, type(str1))  # ... <class 'str'>
print(str2, type(str2))  # b'...' <class 'bytes'>

"""
7.fileObject.writelines(sequence) 向文件写入一个序列字符串列表，如果需要换行则要自己加入每行的换行符 \n
"""
f_7 = open('test.txt', 'w+', encoding='utf-8')
seq = ['我是谁', '我在哪儿', '我要到哪里去', '我的媳妇儿是谁']
print('seq.index', seq.index('我在哪儿'))
seq_str = [i + '\n' for i in seq]
print('seq_str', seq_str)
f_7.writelines(seq_str)
f_7.seek(0, 0)
for each in f_7:
    print(each)
f_7.close()

"""
8.简洁的with语句
一些对象定义了标准的清理行为，无论系统是否成功的使用了它，一旦不需要它了，那么这个标准的清理行为就会执行。
关键词 with 语句就可以保证诸如文件之类的对象在使用完之后一定会正确的执行它的清理方法。

"""
print("===========f_8=============")
try:
    f_8 = open('8.test.txt')
    for line in f_8:
        print(line)
except OSError as error:
    print('f_8 出错啦%s' % str(error))
finally:
    f_8.close()
print("===========f_9=============")

try:
    f_9 = open('8.test.txt')
    for line in f_9:
        print('f_9', line)
except OSError as error:
    print('f_9 出错啦%s' % str(error))
finally:
    f_9.close()
print(1212)
print("===========with=============")

try:
    with open('8.test.txt') as f_10:
        for line in f_10:
            print('f_10', line)
except OSError as error:
    print('f_10 出错啦%s' % str(error))
